package lucene.server.web.controller.websocket;

import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import lucene.server.web.model.WSMessage;
import lucene.server.common.utils.JsonUtil;
import lucene.server.common.utils.StringUtil;
import org.springframework.stereotype.Component;

import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

@Data
@Slf4j
@Component
@ServerEndpoint(value = "/ws/{userId}")
public class WebSocketEndPoint {

    /**
     * 用户ID
     */
    private String userId;

    /**
     * 当前客户端的连接会话, 需要通过它来给客户端发送消息
     */
    private Session session;

    /**
     * WS 会话连接池
     */
    private static ConcurrentHashMap<String, Session> sessionPool = new ConcurrentHashMap<>();

    public static ConcurrentHashMap<String, Session> getSessionPool() {
        return sessionPool;
    }

    @OnOpen
    public void onOpen(Session session, @PathParam(value = "userId") String userId) {
        sessionPool.put(userId, session);
        log.info("【ws-connect】sessionId:{}, userId:{}, 连接总数:{}", session.getId(), userId, sessionPool.size());
        try {
            sendMessageToOne(userId, WSMessage.OK());
        } catch (Exception ex) {
            log.error("【ws】发送连接成功消息异常, userId={}", userId, ex);
        }
    }

    @OnClose
    public void onClose(Session session,CloseReason close) {
        sessionPool.remove(session);
        CloseReason.CloseCode closeCode = close.getCloseCode();
        log.info("【ws-close】userId:{}断开,断开code: {}, 是否正常断开:{} 连接总数:{}", this.userId, closeCode, closeCode == CloseReason.CloseCodes.NORMAL_CLOSURE, sessionPool.size());
    }

    @OnMessage
    public void onMessage(Session session,String message) {
        session.getAsyncRemote().sendText(JsonUtil.toJson(WSMessage.OK()));
        log.info("【ws-message】收到用户[{}]客户端发来的消息:{}", this.userId, message);
    }

    @OnError
    public void onError(Session session, Throwable throwable) {
        log.error("【ws消息】错误{}", this.userId, throwable);
    }

    /**
     * 广播消息
     *
     * @param result 消息内容
     */
    public static void sendMessageToAll(WSMessage result) {
        String jsonMessage = JsonUtil.toJson(result);
        for (Map.Entry<String, Session> entry : sessionPool.entrySet()) {
            Session session = entry.getValue();
            if (StringUtil.isNotNull(session) && session.isOpen()) {
                try {
                    session.getAsyncRemote().sendText(jsonMessage);
                } catch (Exception ex) {
                    log.error("【ws广播消息错误】", ex);
                }
            }
        }
    }
    public static void sendMessageToAll(String message) {
        WSMessage wsMessage = new WSMessage();
        wsMessage.setMessage(message);
        wsMessage.setType("log");
        sendMessageToAll(wsMessage);
    }

    /**
     * 单点消息(单人)
     *
     * @param userId  用户ID
     * @param result 消息内容
     */
    public void sendMessageToOne(String userId, WSMessage result) {
        Session session = sessionPool.get(userId);
        if (StringUtil.isNotNull(session) && session.isOpen()) {
            try {
                session.getAsyncRemote().sendText(JsonUtil.toJson(result));
            } catch (Exception ex) {
                log.error("【ws单点消息错误】", ex);
            }
        }
    }

    /**
     * 获取在线人数
     */
    public Integer onlineUsers() {
        return sessionPool.size();
    }
}